package com.chen.integral.module.test.service.impl;

import com.chen.integral.module.test.service.RuleTestService;
import com.chen.integral.module.test.service.ScriptJsService;
import jdk.nashorn.api.scripting.NashornScriptEngine;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Service;

import javax.script.*;
import java.io.File;
import java.io.FileReader;

/**
 * @Title: manager-spring-mvc-hb
 * @Description: to do
 * @Author: chenjiwei
 * @Date: 2020-11-17 22:52
 * @Version: 1.0.0
 */
@Service
public class ScriptJsServiceImpl implements ScriptJsService {
    /**
     *  使用Script实现java接口
     * @throws Exception
     */
    public void runnableImpl() throws Exception{
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("JavaScript");

        // String里定义一段JavaScript代码脚本
        String script = "function run() { print('run called'); }";
        // 执行这个脚本
        engine.eval(script);

        // 从脚本引擎中获取Runnable接口对象（实例）. 该接口方法由具有相匹配名称的脚本函数实现。
        Invocable inv = (Invocable) engine;
        // 在上面的脚本中，我们已经实现了Runnable接口的run()方法
        Runnable runnable = inv.getInterface(Runnable.class);

        // 启动一个线程运行上面的实现了runnable接口的script脚本
        Thread thread = new Thread(runnable);
        thread.start();
    }

    /**
     * 脚本变量
     * @throws Exception
     */
    @Override
    public void scriptVar() throws Exception {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("JavaScript");
        File file = new File("F:/test/test.txt");
        //将File对象f直接注入到js脚本中并可以作为全局变量使用
        engine.put("files", file);
        engine.eval("print(files.getPath());print(files.getName());");
    }

    @Override
    public void js() throws Exception {
        // 读取js文件 转成String
        String fileStr = FileUtils.readFileToString(new File("F:\\apps-other\\db\\js.js"));
        ScriptEngineManager manager = new ScriptEngineManager();
        // 获取执行引擎
        NashornScriptEngine engine = (NashornScriptEngine) manager.getEngineByName("nashorn");
        // 通过eval方法 执行方法
        ScriptObjectMirror scriptObjectMirror = (ScriptObjectMirror) engine.eval(fileStr);
        // 通过scriptObjectMirror 对象的getMember方法获取对应的返回值
        System.out.println(scriptObjectMirror.getMember("result"));
    }

    @Override
    public void js2(RuleTestService ruleTestService) throws Exception {
        ScriptEngineManager engineManager = new ScriptEngineManager();
        ScriptEngine engineByName = engineManager.getEngineByName("nashorn");//只可写JavaScript或javascript
//            ScriptEngine engineByName = engineManager.getEngineByName("JavaScript");//只可写JavaScript或javascript
        File file = new File("F:\\apps-other\\db\\js.js");//也可以


        //读取js文件
        FileReader reader = new FileReader(file);
        //执行指定脚本
        engineByName.eval(reader);
        if (engineByName instanceof Invocable){// object instanceof class ， object 是 class 的一个实例，则 instanceof 运算符返回 true
            // 注入一个全局的变量ruleService
            engineByName.put("ruleService", ruleTestService);
            Invocable invocable = (Invocable) engineByName;

            //调用merge方法，并传入两个参数
            ScriptObjectMirror func = (ScriptObjectMirror) invocable.invokeFunction("func", 23);
            System.out.println(func.getMember("a")+" "+func.getMember("bool"));
        }
        reader.close();
    }

    @Override
    public void multiScopes() throws Exception {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("nashorn");
        // 打印全局变量 "x"
        engine.put("x", "hello word!!");
        engine.eval("print(x);");
        // 上面的代码会打印"hello word！！"

        // 现在，传入另一个不同的script context
        ScriptContext context = new SimpleScriptContext();
        //新的Script context绑定ScriptContext的ENGINE_SCOPE
        Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE);

        // 增加一个新变脸到新的范围 engineScope 中
        bindings.put("x", "word hello!!");
        // 执行同一个脚本 - 但这次传入一个不同的script context
        engine.eval("print(x);", bindings);
        engine.eval("print(x);");

        //输出结果：
        //hello word!!
        //word hello!!
        //hello word!!
    }


}
